/*
 *  $Id: DefaultLocalizable.cs 1175 2010-11-07 19:52:17Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008-2010 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System.Collections.Generic;

namespace Ragima.Languages {
    /// <summary>
    /// Базовая реализация локализуемого ресурса, с помощью словаря "язык => ресурс".
    /// При этом если язык всего один, то ресурс будет храниться в поле, а не в словаре.
    /// </summary>
    public abstract class DefaultLocalizable<T> : ILocalizable<T> where T : class, ILocalized {
        private T _firstValue;
        private Dictionary<Language, T> _resources;

        public DefaultLocalizable() {
            _firstValue = null;
            _resources = null;
        }

        /// <summary>
        /// Идентификатор ресурса не реализован и оставлен для потомков.
        /// </summary>
        public abstract string ResourceId { get; }

        /// <summary>
        /// Очищает все локализованные ресурсы.
        /// </summary>
        public void ClearResources() {
            _firstValue = null;
            if (_resources != null)
                _resources.Clear();
        }

        /// <summary>
        /// Добавляет локализованную версию ресурса.
        /// </summary>
        public void AddResource(T resource) {
            if (_resources == null && _firstValue == null) {
                _firstValue = resource;
            } else {
                if (_resources == null) {
                    _resources = new Dictionary<Language, T>();
                    _resources.Add(_firstValue.Language, _firstValue);
                    _firstValue = null;
                }
                _resources.Add(resource.Language, resource);
            }
        }

        /// <summary>
        /// Копирует локализованные версии от другого ресурса.
        /// </summary>
        public void CopyFrom(ILocalizable<T> otherResource) {
            foreach (T resource in otherResource.GetResources())
                AddResource(resource);
        }

        /// <summary>
        /// Добавляет ресурсы от всех языков.
        /// </summary>
        public void ForceLocalize() {
            foreach (var lang in Language.AllLanguages.GetLanguages()) {
                if (!HasResource(lang)) {
                    T resource = lang.FindResource<T>(ResourceId);
                    if (resource != null)
                        AddResource(resource);
                }
            }
        }

        /// <summary>
        /// Проверяет наличие уже добавленного ресурса на указанном языке.
        /// </summary>
        public bool HasResource(Language lang) {
            return _resources != null ? _resources.ContainsKey(lang) : (_firstValue != null ? _firstValue.Language == lang : false);
        }

        /// <summary>
        /// Получает локализованную версию ресурса.
        /// Стандартное получение ресурса состоит в поиске по словарю и, если в словаре нет запрашиваемого языка, то выдача ресурса по умолчанию. 
        /// </summary>
        public virtual T GetResource(Language lang) {
            T resource;
            if (_resources != null) {
                if (_resources.TryGetValue(lang, out resource))
                    return resource;
            } else if (_firstValue != null && _firstValue.Language == lang)
                return _firstValue;
            resource = lang.FindResource<T>(ResourceId);
            if (resource != null) {
                AddResource(resource);
                return resource;
            }
            return GetDefaultResource(lang);
        }

        /// <summary>
        /// Получает ресурс указанного типа, определяя язык по типу.
        /// </summary>
        public R GetResource<R>() where R : class, T {
            return GetResource(Language.AllLanguages.GetLanguage<R>()) as R;
        }

        /// <summary>
        /// Получает ресурс по умолчанию. Не реализовано и оставлено для потомков.
        /// </summary>
        public abstract T GetDefaultResource(Language lang);

        /// <summary>
        /// Получает все локализованные ресурсы.
        /// </summary>
        public IEnumerable<T> GetResources() {
            if (_resources != null)
                return _resources.Values;
            else
                return GetFirstValue();
        }
        /// <summary>
        /// Получает единственный ресурс как список.
        /// </summary>
        private IEnumerable<T> GetFirstValue() {
            if (_firstValue != null)
                yield return _firstValue;
        }

        /// <summary>
        /// Получает ресурс для текущего системного языка.
        /// </summary>
        public T GetCurrentResource() {
            return GetResource(Language.CurrentLanguage);
        }
    }
}
